package com.hnzq.cloud.freshorderassembly.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hnzq.cloud.api.FreGoodsAPI;
import com.hnzq.cloud.dto.*;
import com.hnzq.cloud.freshorderassembly.domain.FreGoodsOrder;
import com.hnzq.cloud.freshorderassembly.domain.FreOrder;
import com.hnzq.cloud.freshorderassembly.domain.FreShopcar;
import com.hnzq.cloud.freshorderassembly.exception.FreshException;
import com.hnzq.cloud.freshorderassembly.exception.OrderException;
import com.hnzq.cloud.freshorderassembly.mapper.FreOrderMapper;
import com.hnzq.cloud.freshorderassembly.service.IFreGoodsOrderService;
import com.hnzq.cloud.freshorderassembly.service.IFreOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hnzq.cloud.freshorderassembly.service.IFreShopcarService;
import com.hnzq.cloud.freshorderassembly.util.WoniuBeanUtils;
import com.hnzq.cloud.param.*;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;



/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 周皓月
 * @since 2022-02-06
 */
@Service
public class FreOrderServiceImpl extends ServiceImpl<FreOrderMapper, FreOrder> implements IFreOrderService {

    /**
     * 商品接口
     */
    @Resource
    private FreGoodsAPI goodsAPI;

    /**
     * 购物车接口
     */
    @Resource
    private IFreShopcarService shopcarService;

    /**
     * 订单商品中间表接口
     */
    @Resource
    private IFreGoodsOrderService goodsOrderService;

    /**
     * Redisson
     */
    @Resource
    private RedissonClient redisson;

    /**
     * 类型转换器
     */
    ObjectMapper mapper = new ObjectMapper();



    /**
     * 分页条件查询订单（用户订单展示）
     * @param findOrderParam
     * @return
     */
    @Override
    public PageOrdersDto findOrderByCondition(FindOrderParam findOrderParam) {

        //从登录中获取到userId
        Integer userId = mapper.convertValue(((ServletRequestAttributes)
                (RequestContextHolder.currentRequestAttributes())).getRequest()
                .getHeader("userId"), Integer.class);

        //条件
        QueryWrapper<FreOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete", 0).eq("user_id",userId);



        //订单状态
        if (findOrderParam.getOrderStatus() != null && !findOrderParam.getOrderStatus().equals("")) {
            queryWrapper.eq("order_status",findOrderParam.getOrderStatus());
        }

        //大于等于开始时间
        if ( findOrderParam.getStartTime() != null && !findOrderParam.getStartTime().equals("")) {
            queryWrapper.ge("raw_add_time", findOrderParam.getStartTime());
        }

        //小于等于结束时间
        if (findOrderParam.getEndTime() != null && !findOrderParam.getEndTime().equals("")) {
            queryWrapper.le("raw_add_time", findOrderParam.getEndTime());
        }

        //关键字查询
        if (findOrderParam.getKeyWord() != null && !findOrderParam.getKeyWord().trim().equals("")) {
            queryWrapper.and(qw -> {
                qw.like("order_code", findOrderParam.getKeyWord())
                        .or().like("site_name", findOrderParam.getKeyWord())
                        .or().like("order_payway", findOrderParam.getKeyWord());
            });
        }
        //根据条件进行分页查询
        IPage<FreOrder> iPage = page(new Page<>(findOrderParam.getIndexPage()
                , findOrderParam.getPageSize()),queryWrapper);

        PageOrdersDto pageOrdersDto = new PageOrdersDto();
        pageOrdersDto.setCurrent(iPage.getCurrent());
        pageOrdersDto.setTotal(iPage.getTotal());
        pageOrdersDto.setOrderDtoList(WoniuBeanUtils.copyList(iPage.getRecords(), OrderDto.class));

        return pageOrdersDto;
    }

    /**
     * 根据单个订单id查询订单
     * @param orderId
     * @return
     */
    @Override
    public FreOrder findOrderByOrderId(Integer orderId) {
        //从redis查询对象
        RBucket<Object> bucket = redisson.getBucket("orderId:" + orderId);
        if (!bucket.isExists()){
            //把从数据库查的order对象存放redis
            FreOrder orderDB = getById(orderId);
            if (orderDB == null){
                throw new OrderException("订单不存在",3001);
            }
            bucket.set(orderDB,2,TimeUnit.HOURS);
            return orderDB;
        }

        return ((FreOrder) bucket.get());
    }




    /**
     * 删除订单(逻辑删除)
     * @param removeOrderParam
     * @return
     */
    @Override
    public Boolean removeOrder(RemoveOrderParam removeOrderParam) throws JsonProcessingException {

        //获取锁对象
        RLock lock = redisson.getLock("removeOrder");

        //是否获取锁
        if (lock.tryLock()){

            //从redis查询对象
            RBucket<Object> bucket = redisson.getBucket("orderId:" + removeOrderParam.getOrderId());

            if (!bucket.isExists()){
                FreOrder orderDB = getById(removeOrderParam.getOrderId());
                if (orderDB == null){
                    lock.unlock();
                    throw new OrderException("订单不存在",3001);
                }
                //设置参数后再存redis
                if (removeOrderParam.getIsDelete() != null && !removeOrderParam.getIsDelete().equals("")){
                    orderDB.setIsDelete(removeOrderParam.getIsDelete());
                }
                //把从数据库查的order对象存放redis
                bucket.set(orderDB,2,TimeUnit.HOURS);

                boolean bool = saveOrUpdate(WoniuBeanUtils.copyObject(removeOrderParam, FreOrder.class));
                //操作完数据库后解锁
                lock.unlock();
                return bool;
            }
            boolean bool = saveOrUpdate(WoniuBeanUtils.copyObject(removeOrderParam, FreOrder.class));
            //设置参数后再存redis
            FreOrder redisOrder = (FreOrder) bucket;
            if (removeOrderParam.getIsDelete() != null && !removeOrderParam.getIsDelete().equals("")){
                redisOrder.setIsDelete(removeOrderParam.getIsDelete());
            }
            //把从数据库查的order对象存放redis
            bucket.set(redisOrder,2,TimeUnit.HOURS);
            //操作完数据库后解锁
            lock.unlock();
            return bool;
        }else {
            throw new FreshException("服务器繁忙，请稍后再试",5005);
        }
    }

    /**
     * 新增订单
     * @param addOrderParam
     * @return
     */
    @Override
    public AddOrderDto addOrder(AddOrderParam addOrderParam)  {

//        //从登录中获取到userId
//        Integer userId = 1;

        //雪花计算法，此方法的id不重复
        Snowflake snowflake = new Snowflake(1,1);
        FreOrder freOrder = WoniuBeanUtils.copyObject(addOrderParam, FreOrder.class);
        freOrder.setOrderCode(snowflake.nextId()+"");


        //查购物车的商品ids
        List<Integer> shopcarIds = addOrderParam.getShopcarIds();
        if (shopcarIds == null || shopcarIds.size() <= 0){
            throw new OrderException("未找到要购买的购物车商品",3003);
        }

        //查数据库，找出购物车列表
        List<FreShopcar> shopcarsDBList = shopcarService.listByIds(shopcarIds);

        //将购物车里的每个商品id存入一个List
        List<Integer> goodsIds = shopcarsDBList.stream().map(item -> item.getGoodsId()).collect(Collectors.toList());
        //根据商品多个ids得到商品map集合
        Map<Integer, FreGoodsDto> goodsDtoMap = goodsAPI.findGoodsInfos(goodsIds).getData();

        //订单总原价
        BigDecimal orderOldtotal = new BigDecimal(0);
        //订单总优惠金额
        BigDecimal orderReduce = new BigDecimal(0);
        //订单总实际价格
        BigDecimal orderPayment = new BigDecimal(0);


        //循环传入的购物车商品列表
        for (FreShopcar shopcar : shopcarsDBList) {

            //根据购物车每个商品id获取商品
            FreGoodsDto freGoodsDto = goodsDtoMap.get(shopcar.getGoodsId());

            //得到商品原价
            BigDecimal goodsPrice = freGoodsDto.getGoodsPrice();

            //转换Count属性为decimal
            BigDecimal goodsCount = new BigDecimal(shopcar.getGoodsCount());

            //计算原价
            BigDecimal old = freGoodsDto.getGoodsPrice().multiply(goodsCount);

            orderOldtotal = orderOldtotal.add(old);

            //计算优惠金额
            BigDecimal discount = freGoodsDto.getGoodsPrice()
                    .multiply(freGoodsDto.getGoodsDiscount())
                    .multiply(goodsCount);

            orderReduce = orderReduce.add(discount);

            //计算实际价格
            BigDecimal relPayMent = old.subtract(discount);

            //注意公式格式
            orderPayment = orderPayment.add(relPayMent);
        }

//        System.out.println("计算原价:"+orderOldtotal);
//        System.out.println("计算优惠金额:"+orderReduce);
//        System.out.println("计算实际价格:"+orderPayment);

        //创建新增订单对象
        FreOrder order = new FreOrder();
        order.setOrderCode(freOrder.getOrderCode());
        //TODO 设置userId
        order.setUserId(addOrderParam.getUserId());
        order.setSiteId(addOrderParam.getSiteId());
        order.setSiteName(addOrderParam.getSiteName());
        order.setOrderPayway(null);
        order.setOrderOldtotal(orderOldtotal);
        order.setOrderReduce(orderReduce);
        order.setOrderPayment(orderPayment);

        //执行新增
        if (saveOrUpdate(order)){
            //新增订单成功就新增中间表
            FreOrder orderDB = getOne(new QueryWrapper<FreOrder>().eq("order_code", order.getOrderCode()));

            //循环传入的购物车商品列表
            ArrayList<FreGoodsOrder> goodsOrderList = new ArrayList<>();
            for (FreShopcar shopcar : shopcarsDBList) {

                //根据购物车每个商品id获取商品
                FreGoodsDto freGoodsDto = goodsDtoMap.get(shopcar.getGoodsId());

                if (freGoodsDto == null){
                    throw new OrderException("未找到要购买的购物车商品",3003);
                }
                //准备中间表对象
                FreGoodsOrder freGoodsOrder = new FreGoodsOrder();
                freGoodsOrder.setOrderId(orderDB.getOrderId());
                freGoodsOrder.setGoodsId(freGoodsDto.getGoodsId());
                freGoodsOrder.setGoodsCount(shopcar.getGoodsCount());
                freGoodsOrder.setGoodsPrice(freGoodsDto.getGoodsPrice());
                //添加进集合
                goodsOrderList.add(freGoodsOrder);
            }
            //循环完毕，执行新增
            goodsOrderService.saveOrUpdateBatch(goodsOrderList);
            //新增中间表后，删除购物车商品列表
            ArrayList<Integer> shopcarIdsList = new ArrayList<>();
            //循环传入的购物车商品列表
            for (FreShopcar shopcar : shopcarsDBList) {
                shopcarIdsList.add(shopcar.getShopcarId());
            }
            //执行删除购物车列表
            if (shopcarService.removeByIds(shopcarIdsList)){

                ArrayList<UpdateStockParam> stockParams = new ArrayList<>();

                for (FreShopcar shopcar : shopcarsDBList) {
                    //创建减库存参数对象
                    UpdateStockParam param = new UpdateStockParam();
                    param.setGoodsId(shopcar.getGoodsId());
                    param.setNumber(shopcar.getGoodsCount());
                    //循环加入库存集合
                    stockParams.add(param);
                }

                //执行减少库存操作
                goodsAPI.updateFreGoodsStock(stockParams);

                //最后返回
                return WoniuBeanUtils.copyObject(orderDB,AddOrderDto.class);
            }else {
                throw new OrderException("删除购物车列表失败",3005);
            }
        }else {
            throw new OrderException("新增订单失败",3004);
        }
    }

    /**
     * 根据多个站点id查询所有订单
     * @param findOrderBySiteIdListParam
     * @return
     */
    @Override
    public PageOrdersDto findOrderBySiteIdList(FindOrderBySiteIdListParam findOrderBySiteIdListParam) {
        //查询条件
        QueryWrapper<FreOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete", 0).in("site_id", findOrderBySiteIdListParam.getSiteIds());

        //订单状态
        if ( findOrderBySiteIdListParam.getOrderStatus() != null && !findOrderBySiteIdListParam.getOrderStatus().equals("")) {
            queryWrapper.ge("order_status", findOrderBySiteIdListParam.getOrderStatus());
        }

        //大于等于开始时间
        if ( findOrderBySiteIdListParam.getStartTime() != null && !findOrderBySiteIdListParam.getStartTime().equals("")) {
            queryWrapper.ge("raw_add_time", findOrderBySiteIdListParam.getStartTime());
        }

        //小于等于结束时间
        if (findOrderBySiteIdListParam.getEndTime() != null && !findOrderBySiteIdListParam.getEndTime().equals("")) {
            queryWrapper.le("raw_add_time", findOrderBySiteIdListParam.getEndTime());
        }

        //根据条件进行分页查询
        IPage<FreOrder> iPage = page(new Page<>(findOrderBySiteIdListParam.getIndexPage()
                , findOrderBySiteIdListParam.getPageSize()),queryWrapper);

        //分页对象
        PageOrdersDto pageOrdersDto = new PageOrdersDto();
        pageOrdersDto.setCurrent(iPage.getCurrent());
        pageOrdersDto.setTotal(iPage.getTotal());
        pageOrdersDto.setOrderDtoList(WoniuBeanUtils.copyList(iPage.getRecords(), OrderDto.class));

        return pageOrdersDto;
    }

    /**
     * 根据单个站点id查询所有订单
     * @param findOrderBySiteIdParam
     * @return
     */
    @Override
    public PageOrdersDto findOrderBySiteId(FindOrderBySiteIdParam findOrderBySiteIdParam) {
        //查询条件
        QueryWrapper<FreOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete", 0).in("site_id", findOrderBySiteIdParam.getSiteId());

        //订单状态
        if ( findOrderBySiteIdParam.getOrderStatus() != null && !findOrderBySiteIdParam.getOrderStatus().equals("")) {
            queryWrapper.ge("order_status", findOrderBySiteIdParam.getOrderStatus());
        }

        //大于等于开始时间
        if ( findOrderBySiteIdParam.getStartTime() != null && !findOrderBySiteIdParam.getStartTime().equals("")) {
            queryWrapper.ge("raw_add_time", findOrderBySiteIdParam.getStartTime());
        }

        //小于等于结束时间
        if (findOrderBySiteIdParam.getEndTime() != null && !findOrderBySiteIdParam.getEndTime().equals("")) {
            queryWrapper.le("raw_add_time", findOrderBySiteIdParam.getEndTime());
        }

        //根据条件进行分页查询
        IPage<FreOrder> iPage = page(new Page<>(findOrderBySiteIdParam.getIndexPage()
                , findOrderBySiteIdParam.getPageSize()),queryWrapper);

        //分页对象
        PageOrdersDto pageOrdersDto = new PageOrdersDto();
        pageOrdersDto.setCurrent(iPage.getCurrent());
        pageOrdersDto.setTotal(iPage.getTotal());
        pageOrdersDto.setOrderDtoList(WoniuBeanUtils.copyList(iPage.getRecords(), OrderDto.class));

        return pageOrdersDto;
    }


    /**
     * 判断所有order是否存在所有id列表
     * @param judgeOrderIdsParam
     * @return
     */
    @Override
    public Boolean judgeOrderIds(JudgeOrderIdsParam judgeOrderIdsParam) {
        List<FreOrder> orderListDB = baseMapper.selectBatchIds(judgeOrderIdsParam.getOrderIds());
        if (orderListDB == null || orderListDB.size() == 0){
            throw new OrderException("订单列表不存在",3007);
        }
        //如果参数订单列表长度 == 数据库订单列表长度，返回true
        if (orderListDB.size() == judgeOrderIdsParam.getOrderIds().size()){
            for (FreOrder freOrder : orderListDB) {
                if (freOrder.getOrderStatus()!=judgeOrderIdsParam.getOrderStatus()){
                    return false;
                }
            }
            return true;
        }
        return false;
    }


    /**
     * 修改订单状态
     * @param updateOrderStatusParam
     * @return
     */
    @Override
    public UpdateOrderStatusDto updateOrderStatus(UpdateOrderStatusParam updateOrderStatusParam) throws JsonProcessingException {

        //获取锁对象
        RLock lock = redisson.getLock("updateOrderStatus");

        //是否获取锁
        if (lock.tryLock()){
            //从redis查询对象
            RBucket<Object> bucket = redisson.getBucket("orderId:" + updateOrderStatusParam.getOrderId());

            if (!bucket.isExists()){
                FreOrder orderDB = getById(updateOrderStatusParam.getOrderId());
                if (orderDB == null){
                    lock.unlock();
                    throw new OrderException("订单不存在",3001);
                }
                //设置参数后再存redis
                if (updateOrderStatusParam.getOrderStatus() != null && !updateOrderStatusParam.getOrderStatus().equals("")){
                    orderDB.setOrderStatus(updateOrderStatusParam.getOrderStatus());
                }
                //把从数据库查的order对象存放redis
                bucket.set(orderDB,2,TimeUnit.HOURS);

                //操作数据库
                saveOrUpdate(WoniuBeanUtils.copyObject(updateOrderStatusParam,FreOrder.class));
                //操作完数据库后解锁
                lock.unlock();
                return WoniuBeanUtils.copyObject(updateOrderStatusParam,UpdateOrderStatusDto.class);
            }
            //操作数据库
            saveOrUpdate(WoniuBeanUtils.copyObject(updateOrderStatusParam,FreOrder.class));
            //设置参数后再存redis
            FreOrder redisOrder = (FreOrder) bucket.get();
            if (updateOrderStatusParam.getOrderStatus() != null && !updateOrderStatusParam.getOrderStatus().equals("")){
                redisOrder.setOrderStatus(updateOrderStatusParam.getOrderStatus());
            }
            //把从数据库查的order对象存放redis
            bucket.set(redisOrder,2,TimeUnit.HOURS);

            //操作完数据库后解锁
            lock.unlock();
            return WoniuBeanUtils.copyObject(updateOrderStatusParam,UpdateOrderStatusDto.class);
        }else {
            throw new FreshException("服务器繁忙，请稍后再试",5005);
        }
    }

    /**
     * 修改多个订单的状态
     * @param updateOrderListStatusParam
     * @return
     */
    @Override
    public Integer updateOrderListStatus(UpdateOrderListStatusParam updateOrderListStatusParam) {

        //获取锁对象
        RLock lock = redisson.getLock("updateOrderListStatus");

        //尝试获取锁
        if (lock.tryLock()){
            //查询数据库
            List<FreOrder> orderListDB = baseMapper.selectBatchIds(updateOrderListStatusParam.getOrderIds());
            if (orderListDB == null || orderListDB.size() <= 0){
                lock.unlock();
                throw new OrderException("订单列表不存在",3007);
            }
            for (FreOrder freOrder : orderListDB) {
                freOrder.setOrderStatus(updateOrderListStatusParam.getOrderStatus());
            }
            if (saveOrUpdateBatch(orderListDB)) {
                lock.unlock();
                return updateOrderListStatusParam.getOrderStatus();
            }
            lock.unlock();
            throw new OrderException("修改多个状态失败",3010);
        }else {
            throw new FreshException("服务器繁忙，请稍后再试",5005);
        }
    }

    /**
     * 取消订单
     *
     * @param cancelOrderByOrderIdParam
     * @return
     */
    @Override
    public String cancelOrderByOrderId(CancelOrderByOrderIdParam cancelOrderByOrderIdParam) {

        //获取锁对象
        RLock lock = redisson.getLock("cancelOrderByOrderId");

        //尝试获取锁
        if (lock.tryLock()){
            //从数据库查询对象
            FreOrder orderDB = findOrderByOrderId(cancelOrderByOrderIdParam.getOrderId());
            if (orderDB == null){
                lock.unlock();
                throw new OrderException("订单不存在",3001);
            }
            //更改状态
            orderDB.setOrderStatus(-1);

            saveOrUpdate(orderDB);
            BigDecimal payment = orderDB.getOrderPayment();
            lock.unlock();
            return "订单取消成功，退回金额:"+payment;
        }else {
            throw new FreshException("服务器繁忙，请稍后再试",5005);
        }
    }

}
